﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Data;

namespace Abigail
{
    /// <summary>
    /// This project uses MVC. Kind of.
    /// This class should be the class that mediates between the model, database and the user interface.
    /// </summary>
    public class Controller
    {
        #region Variables and properties
        private Db db;                      // database
        private Form loginWindow;     // the window that asks the user to logon. Is hidden during runtime.

        /// <summary>
        /// The logged in User, and the information for him.
        /// </summary>
        public Model.User LoggedInUser
        {
            get { return loggedInUser; }
            set { loggedInUser = value; }
        }
        private Model.User loggedInUser;     // info for the user that is logged in

        /// <summary>
        /// Gets or sets the string containing public and local IP of the client.
        /// </summary>
        public string IP
        {
            get { return ip; }
        }
        private string ip;


        private List<Model.HeaderList> articleDataTableHeaderList;
        public List<Model.HeaderList> ArticleDataTableHeaderList
        {
            get
            {
                if (articleDataTableHeaderList == null)
                    articleDataTableHeaderList = Db.GetHeaderList();
                return articleDataTableHeaderList; }
        }
        public void ResetArticleHeaderList()
        {
            articleDataTableHeaderList = null;
            articleDataTableHeaderList = Db.GetHeaderList();
        }

        #endregion

        #region Constructors
        /// <summary>
        /// Instanciates the controller with default.
        /// </summary>
        public Controller()
        {
            ip = GetPublicIP();     // fetch ip
            db = new Db(this);      // instanciate
            new Ui.UiLogin(this);   // Ask the user to login:
        }
        #endregion

        #region Application Handling
        /// <summary>
        /// Checks the client local and remote ip
        /// </summary>
        /// <returns>Local and remote Ip as a string.</returns>
        public string GetPublicIP()
        {
            try
            {
                String direction = "?";
                WebRequest request = WebRequest.Create("http://checkip.dyndns.org/");
                using (WebResponse response = request.GetResponse())
                using (StreamReader stream = new StreamReader(response.GetResponseStream()))
                {
                    direction = stream.ReadToEnd();
                }

                //Search for the ip in the html
                int first = direction.IndexOf("Address: ") + 9;
                int last = direction.LastIndexOf("</body>");
                direction = direction.Substring(first, last - first);

                IPHostEntry host;
                string localIP = "?";
                host = Dns.GetHostEntry(Dns.GetHostName());
                foreach (IPAddress ip in host.AddressList)
                {
                    if (ip.AddressFamily.ToString() == "InterNetwork")
                    {
                        localIP = ip.ToString();
                    }
                }
                string returnString = "";
                returnString = String.Format("Publik IP: {0} | Lokal IP: {1}", direction, localIP);
                return returnString;
            }
            catch (Exception)
            {
                Popup.Error("Undantagsfel när IP försökte att avgöras.", "Fel");
            }
            return "Okänd IP";
        }

        /// <summary>
        /// Method that verifies the credentials.
        /// Closes the caller window on success.
        /// </summary>
        /// <param name="caller">The form calling the metod.</param>
        /// <param name="initials">Provided initials</param>
        /// <param name="password">Provided password</param>
        public void DoLogin(Form caller, string initials, string password)
        {
            // Sanitize user input
            initials = Sanitize.Initials(initials);

            Model.User tempUser = db.GetUserFromInitials(initials); // Fetch user for initials to have something to compare to
            if (tempUser == null)   //there is no such user.
            {
                Popup.Warning("Det finns ingen användare med initialerna " + initials, "Fel initialer");
                db.WriteLogWithComment("L0001", "Tried: " + initials); // logg tried initials.
                return;
            }
            if (tempUser.VerifyPassword(password))  // password is correct
            {
                if (tempUser.Activated) // all is good
                {
                    loggedInUser = tempUser;
                    caller.Hide(); // hide login window
                    loginWindow = caller;
                    new Ui.UiMain(this); // open main window
                    db.WriteLogWithComment("L0000", ip); // log success.
                }
                else //the user is inactivated
                {
                    Popup.Warning("Inloggning med initialer " + tempUser.Initials + " är inaktiverat.", "Inaktiverat konto");
                    db.WriteLog("L0002"); // logg inactivated user tried to login
                }
            }
            else
            {
                Popup.Warning("Felaktigt lösenord för initialer " + tempUser.Initials, "Fel lösenord");
                db.WriteLog("L0001"); //logg bad password
            }
        }

        /// <summary>
        /// Logs user off and restart application.
        /// </summary>
        public void DoLogout()
        {
            db.WriteLog("L0004"); // log user logof.
            Application.Restart(); // restart to be sure.
        }

        /// <summary>
        /// Exists the application with no promt
        /// </summary>
        public static void ExitApplication()
        {
            Application.Exit();
        }

        #endregion

        #region Open Ui
        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        public void OpenUiMyAccount() 
        {
            new Ui.UiEditAccount(this, loggedInUser);
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        /// <param name="initials">The initials of the user to be edited</param>
        public void OpenUiEditAccount(string initials)
        {
            initials = Sanitize.Initials(initials);
            if (Sanitize.InitialsHasCorrectLength(initials))
            {
                Model.User user = db.GetUserFromInitials(initials);
                OpenUiEditAccount(db.GetUserFromInitials(initials));
            }
            else
                Popup.Error("Initialerna är inte korrekta.");
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        /// <param name="user">User object to be edited</param>
        private void OpenUiEditAccount(Model.User user)
        {
            new Ui.UiEditAccount(this, user);
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        public void OpenUiAllAccounts() 
        {
            new Ui.UiAllAccounts(this, db.GetAllUsersAsDataTable());
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        public void OpenUiNewAccount() 
        {
            new Ui.UiNewAccount(this);
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        public void OpenUiNewKey() 
        {
            new Ui.UiEditKey(this, db.GetUserInitials());
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        /// <param name="keyName">The key to be edited</param>
        public void OpenUiEditKey(string keyName)
        {
            keyName = Sanitize.Name(keyName);
            if (Sanitize.BetweenLength(keyName, 1, 25))
                new Ui.UiEditKey(this, db.GetUserInitials(), db.GetKeyFromName(keyName));
            else
                Popup.Error("Ogiltig längd på nyckel");
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        public void OpenUiAllKeys() 
        {
            new Ui.UiAllKeys(this, db.GetAllKeysAsDataTable());
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        /// <param name="initials">The initials to be edited</param>
        public void OpenUiEditPassword(string initials)
        {
            // Sanitize user input
            if (initials != null)
            {
                initials = Sanitize.Initials(initials);
                if (!Sanitize.InitialsHasCorrectLength(initials))
                {
                    Popup.Error("Initialerna har otillåten längd");
                    return;
                }
            }

            if(initials == null)
                new Ui.UiEditPassword(this, loggedInUser);
            else if (initials == loggedInUser.Initials)
                new Ui.UiEditPassword(this, loggedInUser);
            else
                new Ui.UiEditPassword(this, db.GetUserFromInitials(initials));
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        /// <param name="areaCode">The area to be edited</param>
        public void OpenUiEditStorageLocationArea(string areaCode)
        {
            areaCode = Sanitize.Initials(areaCode);
            if (!Sanitize.BetweenLength(areaCode, 2, 2))
            {
                Model.StockLocationArea area = db.GetStockLocationAreaFromArea(areaCode);
                new Ui.Article.StockLoc.UiEditStockLocationArea(this, area.Area, area.Definition);
            }
            else
                Popup.Error("Ogiltig områdeskod");
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        public void OpenUiNewStorageLocationArea()
        {
            new Ui.Article.StockLoc.UiEditStockLocationArea(this);
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        public void OpenUiViewStorageLocationAreas()
        {
            new Ui.Article.StockLoc.UiViewAllStockLocationArea(this, db.GetStockLocationAreasAsDataTable());
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        /// <param name="locationId">The location to be edited</param>
        public void OpenUiEditStorageLocation(string locationId)
        {
            Model.StockLocation location;
            try
            {
                location = db.GetStockLocationFromId(int.Parse(locationId));
            }
            catch (Exception e)
            {
                Popup.Error("Fel på lagerplatsid: " + e);
                return;
            }
            
            Model.StockLocationArea[] areas = db.GetStockLocationAreasAsArray();
            int index = 0;
            string[] areasString = new string[areas.Length];

            while (index < areas.Length)
            {
                areasString[index] = String.Format("{0} - {1}", areas[index].Area, areas[index].Definition);
                index++;
            }

            string[] locationValues = new string[5];
            locationValues[0] = location.Id.ToString();
            locationValues[1] = String.Format("{0} - {1}", location.Area.Area, location.Area.Definition);
            locationValues[2] = location.Shelf;
            locationValues[3] = location.Level;
            locationValues[4] = location.Section;

            new Ui.Article.StockLoc.UiEditStockLocation(this, areasString, locationValues);
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        public void OpenUiNewStorageLocation()
        {
            Model.StockLocationArea[] areas = db.GetStockLocationAreasAsArray();
            int index = 0;
            string[] areasString = new string[areas.Length];

            while (index < areas.Length)
            {
                areasString[index] = String.Format("{0} - {1}", areas[index].Area, areas[index].Definition);
                index++;
            }

            new Ui.Article.StockLoc.UiEditStockLocation(this, areasString);
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        public void OpenUiViewStorageLocation()
        {
            new Ui.Article.StockLoc.UiViewAllStockLocation(this, db.GetStockLocationAsDataTable());
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        public void OpenUiNewArticleCategory()
        {
            new Ui.Article.UiEditArticleCategory(this, db.GetArticleCategoriesAsList());
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        /// <param name="id">The id of the category</param>
        /// <param name="name">The name of the category</param>
        /// <param name="main">The id of the main category</param>
        public void OpenUiEditArticleCategory(int id, string name, int main)
        {
            name = Sanitize.Name(name);
            new Ui.Article.UiEditArticleCategory(this, db.GetArticleCategoriesAsList(), id, name, main);
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        /// <param name="id">Id of category to edit</param>
        public void OpenUiEditArticleCategory(int id)
        {
            Model.ArticleCategory cat = db.GetArticleCategoryFromId(id);
            new Ui.Article.UiEditArticleCategory(this, db.GetArticleCategoriesAsList(), id, cat.Name, cat.MainCategory);
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        public void OpenUiViewArticleCategory()
        {
            new Ui.Article.UiViewArticleCategories(this, db.GetArticleCategoriesAsList());
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        public void OpenUiViewArticles()
        {
            new Ui.Article.UiViewArticles(this);
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        /// <param name="id">The article to be edited</param>
        public void OpenUiEditArticle(int id)
        {
            new Ui.Article.UiEditArticle(this, GetCategoryList(), db.GetArticleFromId(id), db.GetUnitTypeArray(),db.GetStockLocationAreaArray(), db.GetStockLocationShelfArray(), db.GetStockLocationLevelArray(), db.GetStockLocationSectionArray());
        }

        /// <summary>
        /// Opens User Interface with suitable data.
        /// </summary>
        public void OpenUiNewArticle()
        {
            new Ui.Article.UiEditArticle(this, GetCategoryList(), db.GetUnitTypeArray(), db.GetStockLocationAreaArray(), db.GetStockLocationShelfArray(), db.GetStockLocationLevelArray(), db.GetStockLocationSectionArray());
        }

        #endregion

        #region ArticleCategory

        /// <summary>
        /// To be used to fetch updated category list
        /// </summary>
        /// <returns>A fresh list of categories</returns>
        public List<Model.ArticleCategory> GetCategoryList()
        {
            return db.GetArticleCategoriesAsList();
        }

        /// <summary>
        /// Saves the category to the database
        /// The caller form will be closed on success.
        /// </summary>
        /// <param name="name">Name to be saved</param>
        /// <param name="main">Id of main category</param>
        /// <param name="caller">Form calling this method</param>
        public void SaveNewArticleCategory(string name, int main, Form caller)
        {
            name = Sanitize.Name(name);
            if (!Sanitize.BetweenLength(name, 2, 40))
            {
                Popup.Error("Ogiltigt namn");
                return;
            }
            SaveNewArticleCategory(new Model.ArticleCategory(0, name, main), caller);
        }

        /// <summary>
        /// Saves the category to the database
        /// The caller form will be closed on success.
        /// </summary>
        /// <param name="category">Category to be saved</param>
        /// <param name="caller">Form calling this method</param>
        private void SaveNewArticleCategory(Model.ArticleCategory category, Form caller)
        {
            if (db.SaveNewArticleCategory(category))
                caller.Close();
        }

        /// <summary>
        /// Updates the given category in database.
        /// The caller form will be closed on success.
        /// </summary>
        /// <param name="id">The id of the category</param>
        /// <param name="name">New name</param>
        /// <param name="main">New id of main category</param>
        /// <param name="caller">Form calling this method.</param>
        public void UpdateArticleCategory(int id, string name, int main, Form caller)
        {
            name = Sanitize.Name(name);
            if (!Sanitize.BetweenLength(name, 2, 40))
            {
                Popup.Error("Ogiltigt namn");
                return;
            }
            UpdateArticleCategory(new Model.ArticleCategory(id, name, main), caller);
        }

        /// <summary>
        /// Updates the given category in the database
        /// The caller form will be closed on success.
        /// Id cannot be changed.
        /// </summary>
        /// <param name="category">The category to be updated.</param>
        /// <param name="caller">Form calling this method.</param>
        private void UpdateArticleCategory(Model.ArticleCategory category, Form caller)
        {
            if (db.UpdateArticleCategory(category))
                caller.Close();
        }

        /// <summary>
        /// Deletes the given category from database
        /// The caller form will be closed on success.
        /// </summary>
        /// <param name="id">The id of the category to be deleted</param>
        /// <param name="caller">Form calling this method</param>
        public void DeleteArticleCategory(int id, Form caller)
        {
            if(Popup.QuestionYesNo("Är du säker på att du vill radera kategorin?", "Sista varningen", "warning"))
                if (db.DeleteArticleCategory(id))
                    caller.Close();
        }
        #endregion

        #region User
        /// <summary>
        /// Fetches a fresh datatable of users from the database.
        /// </summary>
        /// <returns>Fresh datatable from database</returns>
        public DataTable GetUserAsDataTable()
        {
            return db.GetAllUsersAsDataTable();
        }

        /// <summary>
        /// Updates user in database.
        /// Note that password or initials is not updated.
        /// The caller form will be closed on success.
        /// </summary>
        /// <param name="user">The user to be updated, and the new information</param>
        /// <param name="caller">Form calling this method</param>
        private void UpdateUserInfo(Model.User user, Form caller)
        {
            // Sanitize
            user.Name = Sanitize.Name(user.Name);
            user.Phone = Sanitize.Phone(user.Phone);

            if (!Sanitize.EmailIsValid(user.Email)) // if no valid email, abort
            {
                Popup.Error("E-postadressen som du angav verkar inte vara korrekt", "Fel E-post");
                return;
            }

            // Save old information to compare
            Model.User oldUser = db.GetUserFromInitials(user.Initials);
            Console.WriteLine(user.Initials);

            //Try to save the userinfo
            bool success = db.UpdateUser(user);
            if (success)
            {
                //Log information:
                if (user.Initials == loggedInUser.Initials) // the user change his own information
                {
                    if (user.Name != oldUser.Name) //user changed name
                        db.WriteLogWithComment("US008", user.Name + " <- " + oldUser.Name);
                    if (user.Email != oldUser.Email) //user changed email
                        db.WriteLogWithComment("US003", user.Email + " <- " + oldUser.Email);
                    if (user.Phone != oldUser.Phone) //user changed phone
                        db.WriteLogWithComment("US005", user.Phone + " <- " + oldUser.Phone);
                    loggedInUser = db.GetUserFromInitials(loggedInUser.Initials);
                }

                else //user changed others information
                {
                    if (user.Name != oldUser.Name) //user changed name
                        db.WriteLogWithComment("US009", user.Name + " <- " + oldUser.Name);
                    if (user.Email != oldUser.Email) //user changed email
                        db.WriteLogWithComment("US004", user.Email + " <- " + oldUser.Email);
                    if (user.Phone != oldUser.Phone) //user changed phone
                        db.WriteLogWithComment("US006", user.Phone + " <- " + oldUser.Phone);
                    if (user.Activated != oldUser.Activated) // user changed active
                        db.WriteLogWithComment("US010", user.Activated + " <- " + oldUser.Activated);
                }

                caller.Close();
            }
        }

        /// <summary>
        /// Updates user in database.
        /// Note that password or initials is not updated.
        /// The caller form will be closed on success.
        /// </summary>
        /// <param name="initials">User initials that exists in the database</param>
        /// <param name="name">New name</param>
        /// <param name="email">New email</param>
        /// <param name="phone">New phone</param>
        /// <param name="activated">New activated</param>
        /// <param name="caller">The caller of this method</param>
        public void UpdateUserInfo(string initials, string name, string email, string phone, bool activated, Form caller)
        {
            initials = Sanitize.Initials(initials);
            if (!Sanitize.InitialsHasCorrectLength(initials))
            {
                Popup.Error("Initialer är otillåten längd");
                return;
            }

            name = Sanitize.Name(name);
            if (!Sanitize.BetweenLength(name, 2, 30))
            {
                Popup.Error("Namn är otillåten längd");
                return;
            }
            if (!Sanitize.EmailIsValid(email) && email.Length != 0)
            {
                Popup.Error("E-post är ogiltig");
                return;
            }
            phone = Sanitize.Phone(phone);

            UpdateUserInfo(new Model.User(initials, name, "", email, phone, activated), caller);
        }

        /// <summary>
        /// Changes the password of given user
        /// Reads only the user initials
        /// The caller form will be closed on success.
        /// </summary>
        /// <param name="password1">Password to be set</param>
        /// <param name="password2">Retyped password</param>
        /// <param name="user">The user initials</param>
        /// <param name="caller">Form calling this method</param>
        public void ChangePassword(string password1, string password2, string initials, Form caller)
        {
            if (password1 != password2)
            {
                Popup.Error("Lösenorden matchar inte varandra.", "Fel");
                return;
            }

            if (password1.Length < 2)
            {
                Popup.Error("Lösenordet måste vara minst tre tecken långt.", "Fel");
                return;
            }
            Model.User user = db.GetUserFromInitials(initials);
            if (user == null)
            {
                Popup.Error("Ogiltig användare");
                return;
            }
            user.PasswordInText = password1;
            if (db.UpdateUserPassword(user))
            {
                if (user.Initials == loggedInUser.Initials)
                    db.WriteLog("US001"); // log that the user changed own password
                else
                    db.WriteLogWithComment("US002", "For user: " + user.Initials); // log that the user changed other users password

                caller.Close();
            }
            else
                Popup.Error("Fel i databas.", "Fel");
        }

        #endregion

        #region Key
        /// <summary>
        /// Fetches a fresh datatable of keys from the database.
        /// </summary>
        /// <returns>Fresh datatable of keys from database</returns>
        public DataTable GetKeysAsDataTable()
        {
            return db.GetAllKeysAsDataTable();
        }
        
        /// <summary>
        /// Saves a new key to the database
        /// The caller form will be closed on success.
        /// </summary>
        /// <param name="name">Name of the key</param>
        /// <param name="user">The user currently in charge of the key</param>
        /// <param name="caller">Form calling this method</param>
        public void SaveNewKey(string name, string user, Form caller)
        {
            name = Sanitize.Name(name);
            if (!Sanitize.BetweenLength(name, 2, 25))
            {
                Popup.Error("Otillåten längd på nyckel");
                return;
            }

            user = Sanitize.Initials(user);
            if (!Sanitize.InitialsHasCorrectLength(user))
            {
                Popup.Error("Kunde inte identifiera användare.s");
                return;
            }
            Model.Key key = new Model.Key(name, user, DateTime.MinValue);
            key.Name = Sanitize.Name(key.Name);
            if (db.SaveNewKey(key))
            {
                caller.Close();
                db.WriteLogWithComment("KEY01", key.Name + " -> " + key.UserInitials);
            }
        }

        /// <summary>
        /// Updates an existing key in the database.
        /// The name must exists.
        /// The caller form will be closed on success.
        /// </summary>
        /// <param name="name">Name of the key</param>
        /// <param name="user">User currently in charge of the key</param>
        /// <param name="caller">From calling this mehtod.</param>
        public void UpdateKey(string name, string user, Form caller)
        {
            name = Sanitize.Name(name);
            if (!Sanitize.BetweenLength(name, 2, 25))
            {
                Popup.Error("Otillåten längd på nyckel");
                return;
            }

            user = Sanitize.Initials(user);
            if (!Sanitize.InitialsHasCorrectLength(user))
            {
                Popup.Error("Kunde inte identifiera användare.s");
                return;
            }

            Model.Key key = new Model.Key(name, user, DateTime.MinValue);
            if (db.UpdateKey(key))
            {
                caller.Close();
                db.WriteLogWithComment("KEY02", key.Name + " -> " + key.UserInitials);
            }
        }
        #endregion

        #region StockLocation
        /// <summary>
        /// Fetches a fresh datatable from database
        /// </summary>
        /// <returns>StockLocations</returns>
        public DataTable GetStockLocationsAsDataTable()
        {
            return db.GetStockLocationAsDataTable();
        }
       
        /// <summary>
        /// Saves a new location to the database
        /// The caller form will be closed on success.
        /// </summary>
        /// <param name="areaCode">Area code, max 3 characters</param>
        /// <param name="shelf">Shelf, max 2 characters</param>
        /// <param name="level">Level, max 2 characters</param>
        /// <param name="section">Section, max 2 characters</param>
        /// <param name="caller">The form calling this method</param>
        public void SaveNewStockLocation(string areaCode, string shelf, string level, string section, Form caller)
        {
            areaCode = Sanitize.RemoveNonAlphaNumerical(areaCode);
            if (!Sanitize.BetweenLength(areaCode, 1, 2))
            {
                Popup.Error("Ogiltig områdeskod");
                return;
            }
            shelf = Sanitize.RemoveNonAlphaNumerical(shelf);
            if (!Sanitize.BetweenLength(shelf, 1, 3))
            {
                Popup.Error("Ogiltig hyllkod");
                return;
            }
            level = Sanitize.RemoveNonAlphaNumerical(level);
            if (!Sanitize.BetweenLength(level, 1, 2))
            {
                Popup.Error("Ogiltig våning");
                return;
            }
            section = Sanitize.RemoveNonAlphaNumerical(section);
            if (!Sanitize.BetweenLength(section, 1, 2))
            {
                Popup.Error("Ogiltig sektion");
                return;
            }

            Model.StockLocation location = new Model.StockLocation(0, db.GetStockLocationAreaFromArea(areaCode), shelf, level, section);
            if (db.SaveNewStockLocation(location))
                caller.Close();
            else
                Popup.Error("Db svarade med fel");
        }

        /// <summary>
        /// Updates the database with given location.
        /// The caller form will be closed on success.
        /// </summary>
        /// <param name="id">The id of an existing </param>
        /// <param name="areaCode">Area code, max 3 characters</param>
        /// <param name="shelf">Shelf, max 2 characters</param>
        /// <param name="level">Level, max 2 characters</param>
        /// <param name="section">Section, max 2 characters</param>
        /// <param name="caller">The form calling this method</param>
        public void UpdateStockLocation(int id, string areaCode, string shelf, string level, string section, Form caller)
        {
            areaCode = Sanitize.RemoveNonAlphaNumerical(areaCode);
            if (!Sanitize.BetweenLength(areaCode, 1, 2))
            {
                Popup.Error("Ogiltig områdeskod");
                return;
            }
            shelf = Sanitize.RemoveNonAlphaNumerical(shelf);
            if (!Sanitize.BetweenLength(shelf, 1, 3))
            {
                Popup.Error("Ogiltig hyllkod");
                return;
            }
            level = Sanitize.RemoveNonAlphaNumerical(level);
            if (!Sanitize.BetweenLength(level, 1, 2))
            {
                Popup.Error("Ogiltig våning");
                return;
            }
            section = Sanitize.RemoveNonAlphaNumerical(section);
            if (!Sanitize.BetweenLength(section, 1, 2))
            {
                Popup.Error("Ogiltig sektion");
                return;
            }
            Model.StockLocation location = new Model.StockLocation(id, db.GetStockLocationAreaFromArea(areaCode), shelf, level, section);
            if (db.UpdateStockLocation(location))
                caller.Close();
            else
                Popup.Error("Db svarade med fel");
        }
        #endregion

        #region StockLockArea
        /// <summary>
        /// Fetches a fresh datatable from the database.
        /// </summary>
        /// <returns>Fresh datatable of areas</returns>
        public DataTable GetStockLokationAreaAsDataTable()
        {
            return db.GetStockLocationAreasAsDataTable();
        }

        /// <summary>
        /// Saves a new area to the database.
        /// The caller form will be closed on success.
        /// </summary>
        /// <param name="areaCode">The area code, max 2 characters</param>
        /// <param name="definition">The definition of the area</param>
        /// <param name="caller">Form calling this method</param>
        public void SaveNewStockLocationArea(string areaCode, string definition, Form caller)
        {
            areaCode = Sanitize.RemoveNonAlphaNumerical(areaCode);
            if (!Sanitize.BetweenLength(areaCode, 1, 2))
            {
                Popup.Error("Ogiltig områdeskod");
                return;
            }
            definition = Sanitize.Name(definition);
            if (!Sanitize.BetweenLength(definition, 2, 25))
            {
                Popup.Error("Ogiltig definition");
                return;
            }
            Model.StockLocationArea area = new Model.StockLocationArea(areaCode, definition);
            if (db.SaveNewStockLocationArea(area))
                caller.Close();
        }

        /// <summary>
        /// Updates the stocklocationarea in the database
        /// The caller form will be closed on success.
        /// </summary>
        /// <param name="areaCode">The area code, max 2 characters</param>
        /// <param name="definition">The definition of the area</param>
        /// <param name="caller">Form calling this method</param>
        public void UpdateStockLocationArea(string areaCode, string definition, Form caller)
        {
            areaCode = Sanitize.RemoveNonAlphaNumerical(areaCode);
            if (!Sanitize.BetweenLength(areaCode, 1, 2))
            {
                Popup.Error("Ogiltig områdeskod");
                return;
            }
            definition = Sanitize.Name(definition);
            if (!Sanitize.BetweenLength(definition, 2, 25))
            {
                Popup.Error("Ogiltig definition");
                return;
            }
            Model.StockLocationArea area = new Model.StockLocationArea(areaCode, definition);
            if (db.UpdateStockLocationArea(area))
                caller.Close();
            else
                Popup.Error("Db svarade med fel");
        }
        #endregion 

        #region Articles

        public DataTable GetArticlesAsDataTable()
        {
            return db.GetArticlesAsDataTable();
        }

        public bool SaveNewArticle(Model.Article article)
        {
            return db.SaveNewArticle(article);
        }

        public bool UpdateArticle(Model.Article article)
        {
            return db.UpdateArticle(article);
        }

        public void DeleteArticle(Form caller, int id)
        {
            if (db.DeleteArticle(id))
                caller.Close();
        }

        public Model.StockLocation GetStockLocation(string areaDefinition, string shelf, string level, string section)
        {
            Model.StockLocation location = db.GetStockLocationFromAreaShelfLevelSection(areaDefinition, shelf, level, section);
            if(location == null)
            {
                if (Popup.QuestionYesNo("Lagerplatsen finns inte. Vill du skapa den?", "Kunde inte hitta lagerplatsen", "question"))
                {
                    Model.StockLocation temp = new Model.StockLocation(0, db.GetStockLocationAreaFromDefinition(areaDefinition), shelf, level, section);
                    if (db.SaveNewStockLocation(temp))
                        location = db.GetStockLocationFromAreaShelfLevelSection(areaDefinition, shelf, level, section);
                    else
                        return null;
                }
            }
            return location;
        }

        #endregion
    }
}
